#include "ModelManager.h"

namespace nexus {

ModelManager::ModelManager(
    BlockingQueue<std::string>& routeUpdatesQueue,
    BlockingQueue<TopologyUpdate>& topologyUpdatesQueue)
    : routeUpdatesQueue_(routeUpdatesQueue),
      topologyUpdatesQueue_(topologyUpdatesQueue) {
  addFiber([this]() mutable noexcept {
    XLOG(DBG1) << "Starting topo-update task";
    TopologyUpdate update;
    while (true) {
      topologyUpdatesQueue_.read(update); // perform read
      processTopologyUpdate(update);
      // XLOG(INFO) <<
      // std::get<TopologyUpdate::AddDevDetail>(update.detail).name;
    }
    XLOG(DBG1) << "[Exit] topo-update task finished";
  });
  addFiber([this]() mutable noexcept {
    XLOG(DBG1) << "Starting route-update task";
    std::string str;
    while (true) {
      routeUpdatesQueue_.read(str); // perform read
      // if (!maybeThriftObj) {
      //   continue;
      // }
      XLOG(INFO) << str;
      // processDecisionRouteUpdate(std::move(maybeThriftObj).value());
    }
    XLOG(DBG1) << "[Exit] Route-update task finished";
  });
}

void
ModelManager::processTopologyUpdate(TopologyUpdate& update) {
  if (std::holds_alternative<TopologyUpdate::AddDevDetail>(update.detail)) {
    Device dev(std::get<TopologyUpdate::AddDevDetail>(update.detail).name);
    model_.addDevice(dev);
  } else if (std::holds_alternative<TopologyUpdate::AddLinkDetail>(
                 update.detail)) {
    TopologyUpdate::AddLinkDetail& detail =
        std::get<TopologyUpdate::AddLinkDetail>(update.detail);
    XLOG(INFO) << "Adding link: " << detail.srcDev << ":" << detail.srcPort
               << " <-> " << detail.dstDev << ":" << detail.dstPort;
    model_.addLink(
        detail.srcDev, detail.srcPort, detail.dstDev, detail.dstPort);
  } else {
    XLOG(INFO)
        << "Failed to get AddLinkDetail from update.detail, incorrect type stored in variant.";
  }
}

} // namespace nexus